<?php
/**
 * @package nuo
 * @author  Nam Nguyen <nam.ngvan@gmail.com>
 * @version 1.0
 * @since   Apr 22, 2013
 */
class Nuo_Profiler
{

	/**
	 * @var array collected benchmarks
	 */
	protected static $_marks = array();

	/**
	 * Starts a new benchmark and returns a unique token. The returned token
	 * _must_ be used when stopping the benchmark.
	 *
	 *     $token = Nuo_Profiler::start('test', 'profiler');
	 *
	 * @param   string  $group group name
	 * @param   string  $info  profiler information
	 * @return  string
	 */
	public static function start($group, $info = null)
	{
		static $counter = 0;

		// Create a unique token based on the counter
		$token = 'pf/' . base_convert($counter++, 10, 32);

		Nuo_Profiler::$_marks[$token] = array(
			'group' => $group,
			'info' => (string)$info,

			// Start the benchmark
			'start_time' => microtime(TRUE),
			'start_memory' => memory_get_usage(),

			// Set the stop keys without values
			// ended
			'usage_time' => 0,
			'usage_memory' => 0,
		);

		return $token;
	}

	/**
	 * Stops a benchmark.
	 *
	 *     Nuo_Profiler::stop($token);
	 *
	 * @param   string  token
	 * @return  void
	 */
	public static function stop($token)
	{
		if (isset(Nuo_Profiler::$_marks[$token]))
		{
			$mark = Nuo_Profiler::$_marks[$token];

			$memory = memory_get_usage();
			$mark['usage_time'] = microtime(TRUE) - $mark['start_time'];
			$mark['usage_memory'] = memory_get_usage() - $mark['start_memory'];

			Nuo_Profiler::$_marks[$token] = $mark;
		}

	}

	/**
	 * Deletes a benchmark. If an error occurs during the benchmark, it is
	 * recommended to delete the benchmark to prevent statistics from being
	 * adversely affected.
	 *
	 *     Nuo_Profiler::delete($token);
	 *
	 * @param   string  token
	 * @return  void
	 */
	public static function delete($token)
	{
		// Remove the benchmark
		unset(Nuo_Profiler::$_marks[$token]);
	}

	static public function stats()
	{
		$result = array();
		$groups = array();

		foreach (Nuo_Profiler::$_marks as $token => $mark)
		{
			// Sort the tokens by the group and name
			$groups[$mark['group']][] = $mark;
		}

		foreach ($groups as $group => $marks)
		{
			$count = 0;
			$time = 0;
			$memory = 0;
			foreach ($marks as $mark)
			{
				$time += $mark['usage_time'];
				$memory += $mark['usage_memory'];
				$count++;
			}
			$result[$group] = array(
				'usage_time' => $time,
				'usage_memory' => $memory,
				'count' => $count
			);
		}

		unset($groups);
		return $result;
	}

	public static function detail()
	{
		return self::$_marks;
	}

	/**
	 * return data
	 */
	public static function endRequest()
	{
		$time = microtime(1);

		$memory = memory_get_usage(1);

		return array(
			'group' => 'total',
			'usage_time' => ceil(($time - NUO_START_TIME) * 1000),
			'usage_memory' => ceil(($memory - NUO_START_MEMORY) / 1024),
		);
	}

} // End Nuo_Profiler
